﻿//-----------------------------------------------------------------------
// <copyright file="ProcessExtensionsUnitTest.cs" company="CodePlex">
//     Copyright (c) Doug Holland, CodePlex. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace CodePlex.Diagnostics
{
    using System;
    
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;

    using System.Reflection;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    using TypeMock.ArrangeActAssert;

    /// <summary>
    /// Provides unit tests for the <see cref="T:CodePlex.Diagnostics.ProcessExtensions"/> class.
    /// </summary>
    /// <remarks>
    /// <para>
    /// The <see cref="T:ProcessExtensionsUnitTest"/> class depends upon the Typemock Isolator mocking framework available from <see href="http://www.typemock.com"/>.
    /// </para>
    /// <para>
    /// Given that the Typemock Isolator mocking framework is a commerical mocking framework you may need to remove this dependancy to compile CodePlex.Diagnostics.
    /// </para>
    /// <para>
    /// To do this simply remove the references to the Typemock and Typemock.ArrangeActAssert assemblies and also remove the <see cref="T:CodePlex.Diagnistics.ProcessExtensionsUnitTest"/> class
    /// or comment it out although after doing so the <see cref="T:CodePlex.Diagnostics.ProcessExtensions"/> class will have no associated unit tests.
    /// </para>
    /// <para>
    /// The Typemock Isolator mocking framework is necessary to allow the creation of a mock object representing the <see cref="T:System.Diagnostics.Process"/> class
    /// such that the illusion that the current process has exited
    /// </para>
    /// </remarks>
    [Isolated]
    [TestClass]
    public class ProcessExtensionsUnitTest
    {
        #region public ProcessExtensionsUnitTest()

        /// <summary>
        /// Initializes a new instance of the <see cref="T:ProcessExtensionsUnitTest"/> class.
        /// </summary>
        public ProcessExtensionsUnitTest()
        {
        }

        #endregion

        #region public TestContext TestContext

        /// <summary>
        /// Gets or sets the test context which provides information about and functionality for the current test run.
        /// </summary>
        public TestContext TestContext
        {
            get;
            set;
        }

        #endregion

        #region public void ProcessHasExited()

        /// <summary>
        /// Calls the <see cref="M:CodePlex.Diagnostics.ProcessExtensions.UpdateExitDetails"/> when the process is still alive and ensures that an <see cref="T:InvalidOperationException"/> is thrown.
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void ProcessHasExited()
        {
            // establish an instance of the Process class representing the executing vstesthost.exe process.
            Process process = Process.GetCurrentProcess();

            // updating the process exit details when the process is alive will cause an InvalidOperationException to be thrown.
            process.UpdateExitDetails();
        }

        #endregion

        #region public void UpdateExitDetails()

        /// <summary>
        /// Calls the <see cref="M:CodePlex.Diagnostics.ProcessExtensions.UpdateExitDetails"/> when the process has exited and updates the process exit details within the Process table.
        /// </summary>
        [TestMethod]
        public void UpdateExitDetails()
        {
            // establish a mock instance of the Process class.
            var process = Isolate.Fake.Instance<Process>();

            // establish an instance of the Process class representing the executing vstesthost.exe process.
            var currentProcess = Process.GetCurrentProcess();

            // isolate calls to several properties required to give the illusion that the vstesthost.exe process has exited when in fact it is executing this unit test.
            Isolate.WhenCalled(() => process.Id).WillReturn(currentProcess.Id);
            Isolate.WhenCalled(() => process.HasExited).WillReturn(true);
            Isolate.WhenCalled(() => process.StartTime).WillReturn(currentProcess.StartTime);
            Isolate.WhenCalled(() => process.ExitTime).WillReturn(DateTime.Now);
            Isolate.WhenCalled(() => process.ExitCode).WillReturn(0);

            // update the process exit details using the isolated properties established above.
            process.UpdateExitDetails();            
        }

        #endregion
    }
}
